package com.jade.editor.domain.ani;

import java.awt.Polygon;
import java.util.ArrayList;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Region;

import com.jade.editor.domain.parts.ISolve;

public class Anisotropy {

	public static String ANI_DRAWABLE = "DRAWABLE";
	public static String ANI_PLUGABLE = "PLUGABLE";
	
	private AnisotropyModel _model = null;
	private Point _size = null;
	private Region _aniRegion = null;
	private String _type = "DRAWABLE";
	private ISolve _plugAni = null;
	
	private ArrayList<Point> _globalList = new ArrayList<Point>();
	
	/**
	 * Constructor for Drawable Anisotropy
	 * @param model Anisotropy model from file
	 * @param size 
	 */
	public Anisotropy(AnisotropyModel model, Point size){ //TODO replace size with polygon
		_type = Anisotropy.ANI_DRAWABLE;
		_model = model;
		_size = size;
		if (_model != null && _model.getSize() != null)
			initData();
	}
	
	/**
	 * Constructor for Plugable Anisotropy
	 * @param pluginLocation location of plug-in as unique key
	 * @param domain shape
	 */
	public Anisotropy(final String pluginLocation, Point size){ //TODO replace size with polygon
		
		_type = Anisotropy.ANI_PLUGABLE;
		
		int[] polyCoordsX = {size.x};
		int[] polyCoordsY = {size.y};
		Polygon domain = new Polygon(polyCoordsX, polyCoordsY, polyCoordsX.length);
		
		//---
		IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor("com.jade.domain.solve");
		
		try{
			
			for (IConfigurationElement e : config) {
				final Object o = e.createExecutableExtension("class");
				if (o instanceof ISolve) {
					
					ISafeRunnable runnable = new ISafeRunnable() {
						@Override
						public void handleException(Throwable exception) {
							System.out.println("Exception in client");
						}

						@Override
						public void run() throws Exception {
							if (o.getClass().getProtectionDomain().getCodeSource().getLocation().toString().equals(pluginLocation)){
								_plugAni = (ISolve) o;
							}
						}
					};
					SafeRunner.run(runnable);
				}
			}
		}
		catch(CoreException ex){
			System.out.println(ex.getMessage());
		}
		//---
		
		if (_plugAni != null){
			_plugAni.setDomain(domain);
		}
	}
	
	public String getAniType(){
		return _type;
	}
	
	public ISolve getPlugAni(){
		return _plugAni;
	}
	
	
	public void setSize(Point size){
		_size = size;
		if (_model != null && _model.getSize() != null)
			initData();
	}
	
	public void paint(GC gc){
		
		
		if (_type.equals(ANI_DRAWABLE)){
			if (_model != null && _model.getSize() != null){
				
				int countX = _size.x / _model.getSize().x;
				int countY = _size.y / _model.getSize().y;
				
				for(int i = 0, mx = 0; i <= countX; i++, mx += _model.getSize().x){
					for(int j = 0, my = 0; j <= countY; j++, my += _model.getSize().y){
						
						for(Point p : _model.getPointList())
							gc.drawPolygon(point(p.x + mx, p.y + my));
					
						for(Cortege c : _model.getCortegeList())
							c.paint(gc, mx, my);
					}
				}
				
			}
		}
		else if (_type.equals(ANI_PLUGABLE)){
			if (_plugAni != null){
				_plugAni.paint(gc);
			}
		}
		
	}
	
	public AnisotropyModel getAniModel(){
		return _model;
	}
	
	public ArrayList<Point> getPointsList(){
		return _globalList;
	}
	
	private void initData(){
		
		int[] reg = {0,0, _size.x, 0, _size.x,_size.y, 0,_size.y};
		_aniRegion = new Region();
		_aniRegion.add(reg);
		
		_globalList.clear();
		
		int countX = _size.x / _model.getSize().x;
		int countY = _size.y / _model.getSize().y;
		

		for(int i = 0, mx = 0; i <= countX; i++, mx += _model.getSize().x){
			for(int j = 0, my = 0; j <= countY; j++, my += _model.getSize().y){
				
				
				for(Point p : _model.getPointList()){
					Point newp = new Point(p.x + mx, p.y + my);
					if(_aniRegion.contains(newp))
						_globalList.add(newp);
				}
				
				for(Cortege c : _model.getCortegeList()){
					for(Point p : c.getPointsList()){
						Point newp = new Point(p.x + mx, p.y + my);
						if(_aniRegion.contains(newp))
							_globalList.add(newp);
					}
				}
				
			}
		}
	}
	
	private int[] point(int x,int y){
		int poly[] = new int[8];
		int sp = 1;
		poly[0] = x - sp;
		poly[1] = y - sp;
		
		poly[2] = x + sp;
		poly[3] = y - sp;
		
		poly[4] = x + sp;
		poly[5] = y + sp;
		
		poly[6] = x - sp;
		poly[7] = y + sp;
		
		return poly;
	}
	
}
